//
//  WCNewTargetWindowController.m
//  WabbitCode
//
//  Created by William Towe on 1/20/09.
//  Copyright 2009 Revolution Software. All rights reserved.
//

#import "WCNewTargetWindowController.h"
#import "WCMacros.h"
#import "WCProject.h"
#import "NSResponder+WCExtensions.h"
#import "WCNewTargetCategory.h"
#import "WCNewTargetModel.h"
#import "WCNewTargetOutput.h"
#import "WCAppController.h"
#import "WCBuildTarget.h"
#import "NSArray+WCExtensions.h"
#import "WCDocumentController.h"
#import "WCBuildTargetsGroup.h"
#import "NSTreeController+WCExtensions.h"
#import "WCBadgedIconAndTextFieldCell.h"
#import "WCBuildStep.h"
#import "WCProjectGroup.h"
#import "NSOutlineView+WCExtensions.h"
#import "EncodingManager.h"
#import "WCLinkedView.h"
#import "NSPopUpButton+WCExtensions.h"
#import "WCBasicPerformer.h"


NSString *kWCNewTargetTemplateInfoShortDescriptionKey = @"shortDescription";
NSString *kWCNewTargetTemplateInfoLongDescriptionKey = @"longDescription";
NSString *kWCNewTargetTemplateInfoTargetModelKey = @"targetModel";
NSString *kWCNewTargetTemplateInfoTargetOutputKey = @"targetOutput";
NSString *kWCNewTargetTemplateInfoIconNameKey = @"iconName";
NSString *kWCNewTargetTemplateInfoIncludeFilesKey = @"includeFiles";

#define kWCNewTargetModelKey @"model"
#define kWCNewTargetOutputKey @"output"

#define kWCNewTargetTemplateInfoName @"templateInfo.plist"
#define kWCNewTargetTemplatesDirectoryName @"Target Templates"

@interface WCNewTargetWindowController (Private)
- (void)_setupUserInterface;
- (void)_resetUserInterface;
@end

@implementation WCNewTargetWindowController
#pragma mark *** Subclass Overrides ***
- (id)init {
	if (!(self = [super initWithWindowNibName:@"WCNewTargetWindow"]))
		return nil;
	
	_newTargetCategories = [[NSMutableArray alloc] init];
	
	return self;
}

- (void)dealloc {
	[_newTargetCategories release];
	[_newTargetName release];
	[super dealloc];
}

- (void)windowWillLoad {
	[super windowWillLoad];
	
	WCNewTargetCategory *builtInCategory = [WCNewTargetCategory newTargetCategoryWithName:NSLocalizedString(@"Models",@"Models")];
	NSString *targetTemplatesPath = [[NSBundle mainBundle] pathForResource:kWCNewTargetTemplatesDirectoryName ofType:@""];
	
	for (NSString *modelName in [[NSFileManager defaultManager] directoryContentsAtPath:targetTemplatesPath]) {
		WCNewTargetModel *model = [WCNewTargetModel newTargetModelWithName:modelName];
		NSString *modelPath = [targetTemplatesPath stringByAppendingPathComponent:modelName];
		
		for (NSString *outputName in [[NSFileManager defaultManager] directoryContentsAtPath:modelPath]) {
			NSString *templatePath = [modelPath stringByAppendingPathComponent:outputName];
			BOOL isDirectory = NO;
			
			if (![[NSFileManager defaultManager] fileExistsAtPath:templatePath isDirectory:&isDirectory] || !isDirectory)
				continue;
			
			NSString *templateInfoPath = [templatePath stringByAppendingPathComponent:kWCNewTargetTemplateInfoName];
			
			if (![[NSFileManager defaultManager] fileExistsAtPath:templateInfoPath])
				continue;
			
			WCNewTargetOutput *output = [WCNewTargetOutput newTargetOutputWithName:outputName templateInfo:[NSDictionary dictionaryWithContentsOfFile:templateInfoPath] templateDirectory:templatePath];
			
			[[model mutableChildNodes] addObject:output];
		}
		
		if ([[model childNodes] count])
			[[builtInCategory mutableChildNodes] addObject:model];
	}
	
	if ([[builtInCategory childNodes] count])
		[[self newTargetCategories] addObject:builtInCategory];
}

- (void)windowDidLoad {
	[super windowDidLoad];
	
	[[self window] setContentBorderThickness:32.0 forEdge:NSMinYEdge];
	
	[[self window] setTitle:NSLocalizedString(@"New Target",@"new target window title")];
	
	[[self currentView] setFrameSize:[[self swapView] frame].size];
	[[self swapView] addSubview:[self currentView]];
	
	for (NSTreeNode *node in [[[_outlineView dataSource] arrangedObjects] childNodes]) {
		[_outlineView expandItem:node];
	}
	
	[[_outlineView dataSource] setSelectionIndexPath:[[NSIndexPath indexPathWithIndex:0] indexPathByAddingIndex:0]];
}
#pragma mark NSSplitView Delegate
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)offset {
	if ([splitView isVertical])
		return proposedMin + 150.0;
	else if (![splitView isVertical])
		return proposedMin + 100.0;
	return proposedMin;
}

- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)offset {
	if ([splitView isVertical])
		return proposedMax - 250.0;
	else if (![splitView isVertical])
		return proposedMax - 125.0;
	return proposedMax;
}

- (NSRect)splitView:(NSSplitView *)splitView additionalEffectiveRectOfDividerAtIndex:(NSInteger)dividerIndex {
	if ([splitView isVertical]) {
		return NSMakeRect(NSMaxX([_gradientBarView bounds]) - [_leftSplitterHandleImageView frame].size.width, [splitView frame].size.height - [_gradientBarView frame].origin.y - [_gradientBarView bounds].size.height, [_leftSplitterHandleImageView frame].size.width, [_gradientBarView bounds].size.height);
	}
	return NSZeroRect;
}

- (void)splitView:(NSSplitView *)splitView resizeSubviewsWithOldSize:(NSSize)oldSize {
	if ([splitView inLiveResize]) {
		// keep the project outline view and symbols table view the same size while the resizing the middle view
		if ([splitView isVertical]) {
			NSArray *subviews = [splitView subviews];
			NSView *leftView = [subviews objectAtIndex:0];
			NSView *rightView = [subviews lastObject];
			NSRect currentFrame = [splitView frame];
			NSRect leftFrame = [leftView frame];
			NSRect rightFrame = [rightView frame];
			CGFloat dividerThickness = [splitView dividerThickness];
			
			leftFrame.size.height = currentFrame.size.height;
			rightFrame.size.width = currentFrame.size.width - leftFrame.size.width - dividerThickness;
			rightFrame.size.height = currentFrame.size.height;
			rightFrame.origin.x = leftFrame.size.width + dividerThickness;
			
			[leftView setFrame:leftFrame];
			[rightView setFrame:rightFrame];
		}
		// keep the top view in the middle split view the same while resizing the bottom view
		else {
			NSArray *subviews = [splitView subviews];
			NSView *topView = [subviews objectAtIndex:0];
			NSView *bottomView = [subviews lastObject];
			NSRect currentFrame = [splitView frame];
			NSRect topFrame = [topView frame];
			NSRect bottomFrame = [bottomView frame];
			CGFloat dividerThickness = [splitView dividerThickness];
			
			bottomFrame.size.width = currentFrame.size.width;
			topFrame.size.height = currentFrame.size.height - bottomFrame.size.height - dividerThickness;
			topFrame.size.width = currentFrame.size.width;
			bottomFrame.origin.y = topFrame.size.height + dividerThickness;
			
			[topView setFrame:topFrame];
			[bottomView setFrame:bottomFrame];
		}
	}
	else {
		[splitView adjustSubviews];
	}
}
#pragma mark NSOutlineView Delegate
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
	if ([[item representedObject] isKindOfClass:[WCNewTargetModel class]]) {
		[cell setBadgeCount:[[[item representedObject] childNodes] count]];
	}
	else {
		[cell setBadgeCount:0];
	}
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
	return (![[item representedObject] isLeaf]);
}

- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item {
	return [[item representedObject] isLeaf];
}

#pragma mark IBActions
- (IBAction)approveModalWindowAction:(id)sender; {
	if (sender == _collectionView) {
		[self nextAction:nil];
		return;
	}
	
	WCNewTargetOutput *output = [[_arrayController selectedObjects] firstObject];
	if ([[self selectedProject] buildTargetExistsWithModel:[output targetModel] output:[output targetOutput]]) {
		NSString *message = NSLocalizedString(@"Selected Build Target Already Exists",@"duplicate build target alert title");
		NSString *format = NSLocalizedString(@"A build target with the same target model and output already exists in the current project. You cannot have two build targets with the same target model and output.",@"body text for duplicate build target alert");
		NSAlert *alert = [NSAlert alertWithMessageText:message defaultButton:NSLocalizedButtonOK alternateButton:nil otherButton:nil informativeTextWithFormat:format];
		[alert beginSheetModalForWindow:[self window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
		return;
	}
	
	WCBuildTarget *target = [WCBuildTarget buildTargetWithModel:[output targetModel] outputType:[output targetOutput] active:NSUserDefaultsBoolForKey(kWCPrefsNewTargetMakeNewTargetActiveKey)];
	
	WCProjectGroup *projectGroup = [[self selectedProject] projectGroup];
	NSString *projectDirectoryPath = [[self selectedProject] projectFolderPath];
	NSArray *includeFilePaths = nil;
	NSError *error = nil;
	
	if (![[WCBasicPerformer sharedInstance] copyIncludeFiles:[output includeFiles] toProjectDirectory:projectDirectoryPath includedFilePaths:&includeFilePaths error:&error]) {
		// TODO: display the error
	}
	
	NSStringEncoding encoding = NSUserDefaultsUnsignedIntegerForKey(kWCPrefsEditorDefaultFileEncodingKey);
	if (encoding == NoStringEncoding)
		encoding = kWCDefaultFileEncoding;
	
	[projectGroup insertFilePaths:includeFilePaths atIndex:0 copyFiles:NO usingEncoding:encoding];
	
	// copy the active target's build steps into this new target
	if (NSUserDefaultsBoolForKey(kWCPrefsNewTargetCopyActiveTargetsBuildStepsToNewTargetKey)) {
		for (WCBuildStep *step in [[[[self selectedProject] buildTargetsGroup] activeBuildTarget] childNodes]) {
			[[target mutableChildNodes] addObject:[[step copy] autorelease]];
		}
	}
	[target setName:[self newTargetName]];
	// insert the new target
	[[[[self selectedProject] buildTargetsGroup] mutableChildNodes] insertObject:target atIndex:[[self selectedProject] insertionIndexForBuildTargetsGroup]];
	// if this new target is active notify the build targets group of the project
	if ([target isTargetActive])
		[[self selectedProject] setActiveBuildTarget:target];
	// select the new items in the project outline view
	[[[self selectedProject] projectTreeController] selectRepresentedObject:target];
	
	// reset the user interface
	[self _resetUserInterface];
	// dismiss our window
	[super approveModalWindowAction:nil];
}

- (IBAction)dismissModalWindowAction:(id)sender; {
	[self _resetUserInterface];
	[super dismissModalWindowAction:nil];
}
#pragma mark *** Public Methods ***
+ (WCNewTargetWindowController *)sharedInstance; {
	static id controller = nil;
	if (!controller) {
		controller = [[[self class] alloc] init];
	}
	return controller;
}

- (void)presentNewTargetWindow; {
	if (!_hasPerformedSetupForTheFirstTime) {
		_hasPerformedSetupForTheFirstTime = YES;
		// force the window to load so we can set up everything
		(void)[self window];
	}
	
	[self _setupUserInterface];
	
	NSInteger result = [NSApp runModalForWindow:[self window]];
	
	if (result != NSOKButton)
		return;
	
	// save prefs if there are any
}
#pragma mark Accessors
@synthesize newTargetCategories=_newTargetCategories,newTargetName=_newTargetName,swapView=_swapView;

@dynamic currentView;
- (WCLinkedView *)currentView {
	return _currentView;
}
- (void)setCurrentView:(WCLinkedView *)value {
	if (_currentView == value)
		return;
	
	[value setFrameSize:[[self swapView] frame].size];
	[[self swapView] replaceSubview:_currentView with:value];
	_currentView = value;
	
	[[self window] makeFirstResponder:[_currentView firstResponder]];
}

@dynamic selectedProject;
- (WCProject *)selectedProject {
	return [[_addToProjectPopUpButton selectedItem] representedObject];
}
#pragma mark IBActions
- (IBAction)nextAction:(id)sender; {
	WCLinkedView *nextView = [[self currentView] nextView];
	
	if (!nextView) {
		[self approveModalWindowAction:nil];
		return;
	}
	
	[self setCurrentView:nextView];
}

- (IBAction)previousAction:(id)sender; {
	[self setCurrentView:[[self currentView] previousView]];
}
#pragma mark *** Private Methods ***
- (void)_setupUserInterface; {
	// set the initial new target name
	[self setNewTargetName:NSLocalizedString(@"New Target",@"New Target")];
	
	// add the current list of projects
	for (WCProject *project in [[WCDocumentController sharedDocumentController] allProjects]) {
		NSMenuItem *item = [[[NSMenuItem alloc] initWithTitle:[project projectName] action:[_addToProjectPopUpButton action] keyEquivalent:@""] autorelease];
		[item setRepresentedObject:project];
		[[_addToProjectPopUpButton menu] addItem:item];
	}
	
	WCProject *currentProject = [[WCDocumentController sharedDocumentController] currentProject];
	
	// select the current project in the list
	[_addToProjectPopUpButton selectItemWithRepresentedObject:currentProject];
}

- (void)_resetUserInterface; {
	[self setCurrentView:_firstView];
	[_addToProjectPopUpButton removeAllItems];
}
@end
